#include "EWAPrjTimeline.hpp"

#include <json/json.h>

namespace Eyer
{
    EWAPrjTimeline::EWAPrjTimeline()
    {
        EyerSmartPtr<TrackList> videoTrack(new TrackList());
        EyerSmartPtr<TrackList> audioTrack(new TrackList());

        trackSet.insert(std::pair<EWAPrjTrackType, EyerSmartPtr<TrackList>>(EWAPrjTrackType::VIDEO, videoTrack));
        trackSet.insert(std::pair<EWAPrjTrackType, EyerSmartPtr<TrackList>>(EWAPrjTrackType::AUDIO, audioTrack));
    }

    EWAPrjTimeline::~EWAPrjTimeline()
    {
        trackSet.clear();
    }

    int EWAPrjTimeline::GetTrackCount(const EWAPrjTrackType & type)
    {
        std::map<EWAPrjTrackType, EyerSmartPtr<TrackList>>::iterator iter = trackSet.find(type);
        if(iter != trackSet.end()) {
            EyerSmartPtr<TrackList> trackList = iter->second;
            return trackList->size();
        }
        return 0;
    }

    EyerSmartPtr<EWAPrjTrack> EWAPrjTimeline::GetTrack(int index, const EWAPrjTrackType & type)
    {
        std::map<EWAPrjTrackType, EyerSmartPtr<TrackList>>::iterator iter = trackSet.find(type);
        if(iter != trackSet.end()) {
            EyerSmartPtr<TrackList> trackList = iter->second;
            return trackList->at(index);
        }
        return EyerSmartPtr<EWAPrjTrack>(nullptr);
    }

    int EWAPrjTimeline::AddTrack(const EyerSmartPtr<EWAPrjTrack> & track, int index, const EWAPrjTrackType & type)
    {
        for(int i = 0; i < trackListenerList.size(); i++){
            track->RegisterListener(trackListenerList[i]);
        }
        std::map<EWAPrjTrackType, EyerSmartPtr<TrackList>>::iterator iter = trackSet.find(type);
        if(iter != trackSet.end()) {
            EyerSmartPtr<TrackList> trackList = iter->second;
            trackList->insert(trackList->begin() + index, track);
        }
        Update();
        return 0;
    }

    int EWAPrjTimeline::AddTrackBack(const EyerSmartPtr<EWAPrjTrack> & track, const EWAPrjTrackType & type)
    {
        for(int i = 0; i < trackListenerList.size(); i++){
            track->RegisterListener(trackListenerList[i]);
        }
        std::map<EWAPrjTrackType, EyerSmartPtr<TrackList>>::iterator iter = trackSet.find(type);
        if(iter != trackSet.end()) {
            EyerSmartPtr<TrackList> trackList = iter->second;
            trackList->push_back(track);
        }
        Update();
        return 0;
    }

    int EWAPrjTimeline::Parse(const EyerString & json)
    {
        return 0;
    }

    const EyerString EWAPrjTimeline::Serializable()
    {
        Json::Value rootJsonObj;
        rootJsonObj["version"] = 1;
        rootJsonObj["timeline_id"] = Eyer::EyerRand::RandNumberStr(32).c_str();

        Json::Int64 tmstp = EyerTime::GetTime();
        rootJsonObj["create_time"] = tmstp;
        rootJsonObj["modify_time"] = tmstp;

        Json::Value tracksJsonObj;
        {
            EWAPrjTrackType trackType = EWAPrjTrackType::VIDEO;
            for(int i = 0; i < GetTrackCount(trackType); i++){
                EyerSmartPtr<EWAPrjTrack> track = GetTrack(i, trackType);
                if(track == nullptr){
                    continue;
                }
                Json::Value trackJsonObj;
                trackJsonObj["track_id"] = track->GetTrackId().c_str();

                {
                    Json::Value fragmentListJsonObj;
                    int fragmentCount = track->GetFragmentCount();
                    for(int j = 0; j < fragmentCount; j++){
                        EyerSmartPtr<EWAPrjFragment> fragment = track->GetFragment(j);
                        Json::Value fragmentJsonObj;
                        fragmentJsonObj["margin_left"] = fragment->GetMarginLeft();
                        fragmentJsonObj["block_start_time"] = fragment->GetBlockStartTime();
                        fragmentJsonObj["block_end_time"] = fragment->GetBlockEndTime();
                        fragmentListJsonObj.append(fragmentJsonObj);
                    }
                    trackJsonObj["fragment_list"] = fragmentListJsonObj;
                }

                tracksJsonObj.append(trackJsonObj);
            }
        }
        rootJsonObj["tracks"] = tracksJsonObj;

        EyerString json = rootJsonObj.toStyledString();
        return json;
    }

    int EWAPrjTimeline::RegisterListener(EWAPrjTimelineListener * listener)
    {
        listenerList.push_back(listener);
        return 0;
    }

    int EWAPrjTimeline::UnregisterListener(EWAPrjTimelineListener * listener)
    {
        for(auto it = listenerList.begin(); it != listenerList.end(); ) {
            if(*it == listener) {
                listenerList.erase(it);
            } else {
                it++;
            }
        }
        return 0;
    }

    int EWAPrjTimeline::RegisterTrackListener(EWAPrjTrackListener * listener)
    {
        trackListenerList.push_back(listener);
        return 0;
    }

    int EWAPrjTimeline::UnregisterTrackListener(EWAPrjTrackListener * listener)
    {
        for(auto it = trackListenerList.begin(); it != trackListenerList.end(); ) {
            if(*it == listener) {
                trackListenerList.erase(it);
            } else {
                it++;
            }
        }
        return 0;
    }

    int EWAPrjTimeline::Update()
    {
        for(int i = 0; i < listenerList.size(); i++){
            listenerList[i]->OnTrackUpdate(this);
        }
        return 0;
    }
}